<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue 学习</title>
</head>

<body>

    <h2>快速简介</h2>
    <div id="app">
        {{ message }}
    </div>

    <!-- v-bind 绑定el属性 的使用 -->
    <div id="app-2">
        <span v-bind:title="message">
            鼠标悬停几秒钟查看此处动态绑定的提示信息！
        </span>
    </div>

    <!-- v-if 条件渲染 -->
    <div id="app-3">
        <p v-if="seen">现在你看到我了，但是几秒后我就不见了</p>
    </div>

    <!-- v-for 循环渲染 -->
    <div id="app-4">
        <ol>
            <li v-for="todo in todos">
                {{ todo.text }}
            </li>
        </ol>
    </div>

    <!-- v-on 事件响应 -->
    <div id="app-5">
        <p>{{ message }}</p>
        <button v-on:click="reverseMessage">反转消息</button>
    </div>

    <!-- v-model 表单输入绑定 -->
    <div id="app-6">
        <p>{{ message }}</p>
        <input v-model="message">
    </div>

    <br>
    <br>
    <h2>组件化</h2>
    <hr>
    <hr>
    <br>
    <h3>组件化1</h3>
    <div id="app-7">
        <ol>
            <!--
            现在我们为每个 todo-item 提供 todo 对象
            todo 对象是变量，即其内容可以是动态的。
            我们也需要为每个组件提供一个“key”，稍后再
            作详细解释。
          -->
            <todo-item v-for="item in groceryList" v-bind:todo="item" v-bind:key="item.id">

            </todo-item>
        </ol>
    </div>

    <br>
    <h2>模板语法</h2>
    <h3>v-once</h3>
    <p>v-once表标 只执行一次 例如这样 : &lt;span v-once&gt;这个将不会改变: {{ msg }}&lt;/span&gt;</p>
    <h3>v-html</h3>
    <p>v-html表标 绑定的html原始字符串直接转到模板 <br> 例如 : &lt;p&gt;Using v-html directive: &lt;span
        v-html="rawHtml"&gt;&lt;/span&gt;&lt;/p&gt; </p>
    <div id="v-html">
        <span v-html="rawHtml"></span></p>
    </div>
    <h3>v-bind</h3>
    <p>v-bind 用于绑定元素的属性 例如： &lt;div v-bind:id="dynamicId"&gt;&lt;/div&gt; </p>

    <h3>使用 JavaScript 表达式</h3>
    <p>下面的表达式都是常见的，{{}}内不能执行多于一条js语句</p>
    <p style="background-color: lightgrey;">
        {{ number + 1 }} <br>

        {{ ok ? 'YES' : 'NO' }} <br>

        {{ message.split('').reverse().join('') }} <br>
    </p>
    <p>这些是不生效的</p>
    <p style="background-color: lightgrey;">
        这是语句，不是表达式
        {{ var a = 1 }} <br>

        流控制也不会生效，请使用三元表达式
        {{ if (ok) { return message } }} <br>
    </p>
    <br>
    <p>属性也可以用表达式</p>
    <p style="background-color: lightgrey;">
        &lt;div v-bind:id="'list-' + id"&gt;&lt;/div&gt;
    </p>

    <h3>动态参数</h3>
    <div id="dync-attr">
        <p v-bind:[attr]="value">
            写成这样，v-bind:[attr]="value"，<br> attr value都会被替换成vue的绑定data成员
        </p>
    </div>

    <h3>修饰符</h3>
    <p>修饰符 (modifier) 是以半角句号 . 指明的特殊后缀，用于指出一个指令应该以特殊方式绑定。<br>例如，.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault()：
    </p>
    <p style="background-color: lightgrey;">
        &lt;form v-on:submit.prevent="onSubmit"&gt;...&lt;/form&gt;
    </p>

    <h3>缩写</h3>
    <ul>
        <li>v-bind 缩写 ':' </li>
        <li>v-on 缩写 '@'</li>
    </ul>

    <h2>计算属性和侦听器</h2>
    <h3>computed 计算例子</h3>
    <div id="computed-demo">
        <p>原始信息: "{{ message }}"</p>
        <p>计算返回信息的反转: "{{ reversedMessage }}"</p>
    </div>

    <h3>侦听属性</h3>
    <div id="watch-demo">
        <p>{{ fullName }}</p>
        <br>
        <input type="button" value="使用setter更改vue绑定"></input>
        <br>
    </div>

    <br>
    <br>
    <h2>Class 与 Style 绑定</h2>
    <hr>
    <h3>绑定 HTML Class 条件使能class内容</h3>
    <div v-bind:class="{ active: isActive }"></div>
    <!-- 上面的语法表示 active 这个 class 存在与否将取决于数据 property isActive是否为true -->

    <div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>
    <!-- 当 isActive=true hasError=false 会生成下面的结果 -->
    <div class="static active"></div>

    <br>
    <br>
    <h2>深入了解组件</h2>
    <hr>
    <!-- 自定义组件事件 -->
    <component-even id="component-e1" style="background-color: lightgrey;" v-bind:post="msg" v-on:def-even1="changemsg">
    </component-even>

    <br>
    <br>

    <div id="custom-input-demo" style="background-color: lightgrey;">
        <custom-input v-model="searchText"></custom-input>
        <!-- 自定义组件中使用 v-model 等价于 : -->
        <!-- <custom-input v-bind:value="searchText" v-on:input="searchText = $event"></custom-input> -->
        <p>输入了： {{searchText}} </p>
    </div>

    <table width="900" cellspacing="1" cellpadding="1" border="1">
        <caption align="top">DOM 原生事件 转入event对象成员</caption>
        <tbody>
            <tr>
                <td><span style="font-size: 18px">属性/方法</span></td>
                <td><span style="font-size: 18px">类型</span></td>
                <td><span style="font-size: 18px">是否可读写</span></td>
                <td><span style="font-size: 18px">描写叙述</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">altKey</span></td>
                <td><span style="font-size: 18px">Boolean</span></td>
                <td><span style="font-size: 18px">读写</span></td>
                <td><span style="font-size: 18px">指示是否按下alt键</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">bubbles</span></td>
                <td><span style="font-size: 18px">Boolean</span></td>
                <td><span style="font-size: 18px">读<span style="white-space: pre"> </span></span></td>
                <td><span style="font-size: 18px">指示事件是否冒泡</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">button</span></td>
                <td><span style="font-size: 18px">Intrger</span></td>
                <td><span style="font-size: 18px">读写</span></td>
                <td>
                    <p><span style="font-size: 18px">鼠标事件发生时候按下的鼠标button。</span></p>
                    <p><span style="font-size: 18px">0-没有按鼠标button</span></p>
                    <p><span style="font-size: 18px">1-按了鼠标右键</span></p>
                    <p><span style="font-size: 18px">3-按了鼠标左键</span></p>
                    <p><span style="font-size: 18px">4-按了鼠标中间button</span></p>
                    <p><span style="font-size: 18px">5-同一时候按下鼠标左button和中间button</span></p>
                    <p><span style="font-size: 18px">6-同一时候按下鼠标右button和中间button</span></p>
                    <p><span style="font-size: 18px">7-同一时候按下左中右三个button</span></p>
                </td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">cancelable</span></td>
                <td><span style="font-size: 18px">Boolean</span></td>
                <td><span style="font-size: 18px">读</span></td>
                <td><span style="font-size: 18px">指示事件能否够被取消</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">cancelBubble</span></td>
                <td><span style="font-size: 18px">Boolean</span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px">指示事件冒泡是否已经被取消</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">charCode</span></td>
                <td><span style="font-size: 18px">Integer</span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px">被按下的键的Unicode字符集</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">clientX</span></td>
                <td><span style="font-size: 18px">Integer</span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px">事件发生时，鼠标指针在客户区（不包含工具栏、滚动栏等）的X坐标</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">clientY<br>
                    </span></td>
                <td><span style="font-size: 18px">Integer<br>
                    </span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px">事件发生时，鼠标指针在客户区（不包含工具栏、滚动栏等）的Y坐标<br>
                    </span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px"><span
                            style="font-family: Arial; line-height: 26px">ctrlKey</span><span
                            style="font-family: Arial; line-height: 26px; white-space: pre"></span><span
                            style="font-family: Arial; line-height: 26px">&nbsp; &nbsp;</span><br>
                    </span></td>
                <td><span style="font-size: 18px"><span
                            style="font-family: Arial; line-height: 26px">&nbsp;Boolean</span><br>
                    </span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px"><span
                            style="font-family: Arial; font-size: 18px; line-height: 26px">指示是否按下了ctrl键</span><br>
                    </span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px"><span
                            style="font-family: Arial; font-size: 18px; line-height: 26px">fromElement&nbsp;</span><br>
                    </span></td>
                <td><span style="font-size: 18px"><span
                            style="font-family: Arial; font-size: 18px; line-height: 26px">Element</span><br>
                    </span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px"><span
                            style="font-family: Arial; font-size: 18px; line-height: 26px">在鼠标事件中鼠标移出的元素</span><br>
                    </span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">detail</span></td>
                <td><span style="font-size: 18px">Integer</span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px">鼠标button被点击的次数</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">eventPhase</span></td>
                <td><span style="font-size: 18px">Integer</span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td>
                    <p><span style="font-size: 18px">事件的阶段。其职为：</span></p>
                    <p><span style="font-size: 18px">0-捕获节点</span></p>
                    <p><span style="font-size: 18px">1-在目标上</span></p>
                    <p><span style="font-size: 18px">3-冒泡阶段</span></p>
                </td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">isChar</span></td>
                <td><span style="font-size: 18px">Boolean</span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td>
                    <p><span style="font-size: 18px">指示被按下的键盘的数字表示器</span></p>
                </td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">keyCode</span></td>
                <td><span style="font-size: 18px">Integer</span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px">指示按下的键盘的数字表示器</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">pageX</span></td>
                <td><span style="font-size: 18px">Integer</span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px">鼠标指针相对于页面的X坐标</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px"><span style="font-size: 18px">pageY</span><br>
                    </span></td>
                <td><span style="font-size: 18px"><span style="font-size: 18px">Integer</span><br>
                    </span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px"><span style="font-size: 18px">鼠标指针相对于页面的Y坐标</span><br>
                    </span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">preventDefault()</span></td>
                <td><span style="font-size: 18px">Function</span></td>
                <td><span style="font-size: 18px"><br>
                    </span></td>
                <td><span style="font-size: 18px">调用此方法能够阻止事件的默认行为</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">relatedTarget</span></td>
                <td><span style="font-size: 18px">Element</span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px">事件的下一个目标，经经常使用在鼠标事件中</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px"><span
                            style="font-family: Arial; font-size: 18px; line-height: 26px">screenX</span><br>
                    </span></td>
                <td><span style="font-size: 18px"><span style="font-size: 18px">Integer</span><br>
                    </span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px"><span
                            style="font-family: Arial; font-size: 18px; line-height: 26px">鼠标指针相对于整个计算机屏幕的X坐标</span><br>
                    </span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px"><span
                            style="font-family: Arial; font-size: 18px; line-height: 26px">screenY</span><br>
                    </span></td>
                <td><span style="font-size: 18px"><span style="font-size: 18px">Integer</span><br>
                    </span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px"><span
                            style="font-family: Arial; font-size: 18px; line-height: 26px">鼠标指针相对于整个计算机屏幕的Y坐标</span><br>
                    </span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">shiftKey</span></td>
                <td><span style="font-size: 18px">Boolean</span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px">指示是否按下shift键</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">stopPropagation()</span></td>
                <td><span style="font-size: 18px">Function</span></td>
                <td><span style="font-size: 18px"><br>
                    </span></td>
                <td><span style="font-size: 18px">调用该方法，能够阻止时间的进一步传播（冒泡）</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">target</span></td>
                <td><span style="font-size: 18px">Element</span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px">触发的事件元素/对象</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">timeStamp</span></td>
                <td><span style="font-size: 18px">long</span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px">事件发生的时间(当前时间减去1970年1月1日午夜后的微秒数)</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px">type</span></td>
                <td><span style="font-size: 18px">Strin</span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px">事件的名称</span></td>
            </tr>
            <tr>
                <td><span style="font-size: 18px"><br>
                    </span></td>
                <td><span style="font-size: 18px"><br>
                    </span></td>
                <td><span style="font-size: 18px">读<br>
                    </span></td>
                <td><span style="font-size: 18px"><br>
                    </span></td>
            </tr>
        </tbody>
    </table>


    <br>
    <br>
    <div id="slot-demo1" style="background-color: lightgrey;">
        <h4>插槽的使用</h4>
        <alert-box style="background-color: lightpink;">
            这里的信息替换到了组件模板的 &lt;slot&gt; &lt;/slot&gt; 里面
        </alert-box>
    </div>

    <br>
    <br>
    <div id="name-slot-demo" style="background-color: lightpink;">
        <h5>命名插槽</h5>
        <name-slot-div>
            <template v-slot:footer>
                <h6 style="background-color: cadetblue;">放置到 带属性 name="footer" 里</h6>
            </template>
            <p>默认的没带名字的插槽</p>
            <p>v-slot只能出现在 &lt;template&gt; 标签里</p>
            <p>也可以在 &lt;template&gt; 标签里写上 v-slot:default 指定为默认插槽</p>
            <template v-slot:header>
                <h6 style="background-color: cyan;">放置到 带属性 name="header" 里</h6>
            </template>

            <!-- 动态插槽名可以这样写  <template v-slot:[dynamicSlotName]></template> -->
            <!-- v-slot:header 可以被缩写为 #header -->
        </name-slot-div>
    </div>


    <br>
    <br>
    <div id="slot-prop-demo" style="background-color:lightgrey">
        <h4>prop 插槽示例</h4>
        <slot-prop-div>
            <template v-slot:default="slotProps">
                <p>仅仅通过 user.firstName 是访问不到组件中的内容的</p>
                通过组件中&lt;slot&gt;的v-bind 向暴露user对象到插槽的prop属性，<br>
                父级通过slot 读取到的组件中内容为： {{ slotProps.shell.firstName }}
            </template>
        </slot-prop-div>
        <br>
        <!-- 整个组件的内容为默认匿名插槽时也可以这样写 -->
        <slot-prop-div v-slot="defslotprop">
            整个组件默认插槽同 通过v-slot='' 读取到的组件中内容为： {{ defslotprop.shell.firstName }}
        </slot-prop-div>
    </div>

    <br>
    <br>
    <div id='dync-component-demo' style="background-color: lightgrey;">
        <h5>动态组件示例</h5>
        <ol>
            <component v-bind:is="'todo-item'" v-bind:todo="{id:0,text:'todo-item'}"></component>
            <component v-for="item in dync1_list" v-bind:is="dync1" v-bind:todo="item"></component>
            <li v-for="(count,index) in 3">
                <component v-bind:is='dync2'></component>
            </li>
        </ol>

        <!-- 使用 keep-alive 失活的组件将会被缓存！-->
        <keep-alive>
            <component v-bind:is="'currentTabComponent'"></component>
        </keep-alive>
    </div>

    <br>
    <br>
    <h2>可复用性 & 组合</h2>
    <hr>
    <h4>混入 mixin</h4>
    <div id='mixinflag'></div>

    <br>
    <div id="mixin-opt-merge"></div>

    <br>
    <h4>render函数代替template生成dom</h4>
    <div id="vue-render-demo">
        <vue-render-demo v-bind:level='level'>看吧生成了 h6标题了</vue-render-demo>
    </div>

    <br>
    <div id="vue-compile-demo"></div>

    <br>
    <h4>render函数代替template生成dom 2</h4>
    <div id="vue-render-demo1">
        vue-render-demo1
    </div>

    <br>
    <br>
    <h1>vue router 学习</h1>

    <div id="router-demo1">
        <h3>基本的router使用</h3>
        <p>
            <!-- 使用 router-link 组件来导航. -->
            <!-- 通过传入 `to` 属性指定链接. -->
            <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
            <router-link to="/foo">Go to Foo</router-link>
            <br>
            <router-link to="/bar">Go to Bar</router-link>
        </p>
        <!-- 路由出口 -->
        <!-- 路由匹配到的组件将渲染在 router-view 标签位置-->


        <br>
        <div id="router-demo2">
            <h3>动态 router使用</h3>
            <router-link to="/user/:user1">跳转到user1</router-link>
            <br>
            <router-link to="/user/:user2">跳转到user2</router-link>
            <router-view></router-view>
        </div>

        <br>
        <br>

        <router-view></router-view>
        <table width="600" border="1">
            <caption>路径的其它动态匹配示例 </caption>
            <thead>
                <tr>
                    <th>模式</th>
                    <th>匹配路径</th>
                    <th>$route.params</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>/user/:username</td>
                    <td>/user/evan</td>
                    <td><code>{ username: 'evan' }</code></td>
                </tr>
                <tr>
                    <td>/user/:username/post/:post_id</td>
                    <td>/user/evan/post/123</td>
                    <td><code>{ username: 'evan', post_id: '123' }</code></td>
                </tr>
            </tbody>
        </table>
    </div>

    <br>
    <br>
    <div id="router-demo3" style="background-color: lightgrey;">
        <h3>嵌套 router使用</h3>
        <router-link to="/embeddedview/foo">跳转到嵌套router首层</router-link>
        <br>
        <router-view></router-view>
    </div>

    <br>
    <br>
    <div style="background-color: lightgrey;">
        <h3>编程式router使用</h3>
        <div id="router-demo4"></div>
    </div>

    <br>
    <br>
    <div id="router-demo5" style="background-color: lightgrey;">
        <h3>命名路由</h3>
        <router-link v-bind:to="{ name: 'namedrouter', params: { userId: 123 }}">跳转到命名路由</router-link>
        <br>
        <router-view></router-view>
    </div>

    <br>
    <br>
    <div id="router-demo6" style="background-color: lightgrey;">
        <h3>命名视图</h3>
        <router-link to="/nameview">跳转到命名视图</router-link>
        <br>
        <!-- <router-view></router-view>相当于是 <router-view name="default"></router-view> -->
        <router-view></router-view>
        <router-view name='v1'></router-view>
        <router-view name='v2'></router-view>
    </div>

    <br>
    <br>
    <div id="router-demo7" style="background-color: lightgrey;">
        <h3>路由组件传参</h3>
        <div></div>
        <router-link to="/proptovue/1003">跳转到路由组件传参测试</router-link>
        <br>
        <router-link to="/proptovue-object/test">跳转到路由组件传参 对象模式</router-link>
        <br>
        <router-link to="/proptovue-method/search?q=vue">跳转到路由组件传参 函数模式</router-link>
        <router-view></router-view>
    </div>


    <!-- *****************************下面是script了********************************************* -->

    <!-- 开发环境版本，包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <!-- 生产环境版本，优化了尺寸和速度 -->
    <!-- <script src="https://cdn.jsdelivr.net/npm/vue"></script> -->

    <!-- vue-router cdn -->
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

    <script>
        var app = new Vue(
            {
                el: "#app", //选择子 选择要绑定的元素
                data: {     //响应式数据定义
                    message: "Hello world!"
                }
            }
        )

        var app2 = new Vue(
            {
                el: "#app-2",
                data: {
                    message: '页面加载于 ' + new Date().toLocaleString()
                }
            }
        )

        var app3 = new Vue({
            el: '#app-3',
            data: {
                seen: true
            }
        })

        setTimeout("app3.seen=false", 3000)

        var app4 = new Vue({
            el: '#app-4',
            data: {
                todos: [
                    { text: '学习 JavaScript' },
                    { text: '学习 Vue' },
                    { text: '整个牛项目' }
                ]
            }
        })

        var app5 = new Vue({
            el: '#app-5',
            data: {
                message: 'Hello Vue.js!'
            },
            methods: {
                reverseMessage: function () {
                    this.message = this.message.split('').reverse().join('')
                }
            }
        })

        var app6 = new Vue({
            el: '#app-6',
            data: {
                message: 'Hello Vue!'
            }
        })

        Vue.component('todo-item', {
            // todo-item 组件现在接受一个
            // props 成员，返回一个数组，声明本组件的模板可以从父实例接收到象的element属性集
            //其实就是声明 todo-item 组件有一个'todo'属性 可用于接收object 然后用于渲染
            //这样做的好处是，不同的vue实例，这个组件可以做出不同的渲染
            props: ['todo'],
            template: '<li>{{ todo.text }}, id = {{ todo.id }}</li>'    //渲染模板
        })

        var app7 = new Vue({
            el: '#app-7',   //这个是父实例
            data: {
                groceryList: [      //todo-item 组件的 'todo'属性接收这个对象里的值
                    { id: 0, text: '蔬菜' },
                    { id: 1, text: '奶酪' },
                    { id: 2, text: '随便其它什么人吃的东西' }
                ]
            }
        })

        var d1 = document.createElement("div")
        d1.setAttribute("style", "background-color:gray;height:50px")
        d1.textContent = app7.$el.outerHTML
        app7.$el.append(d1)

        var vvhtml = new Vue(
            {
                el: "#v-html",
                data: {
                    rawHtml: "<div style='background-color:gray;height:50px'>span转为了div了</div>"
                }
            }
        )

        var dync_attr = new Vue(
            {
                el: "#dync-attr",
                data: {
                    attr: "style",
                    value: "background-color:lightgrey"
                }
            }
        )
        document.createElement("div")
        d1.setAttribute("style", "background-color:gray;height:50px")
        d1.textContent = dync_attr.$el.outerHTML
        dync_attr.$el.append(d1)

        var computed_demo = new Vue(
            {
                el: "#computed-demo",
                data: {
                    message: "Hello"
                },
                computed: {
                    // 计算属性的 getter
                    reversedMessage: function () {
                        // `this` 指向 vm 实例
                        return this.message.split('').reverse().join('')
                    }
                }
            }
        )

        var watch_demo = new Vue({
            el: '#watch-demo',
            data: {
                firstName: 'Foo',
                lastName: 'Bar',
                fullName: 'Foo Bar'
            },
            watch: {
                firstName: function (val) {
                    this.fullName = val + ' ' + this.lastName
                },
                lastName: function (val) {
                    this.fullName = this.firstName + ' ' + val
                }
            }
        })


        //console.log(watch_demo.$el.getElementsByTagName('input')[0].attributes)
        var e = watch_demo.$el
        watch_demo.$el.children[0].textContent = "{{ fullName }}"
        watch_demo.$el.getElementsByTagName('input')[0].setAttribute('v-on:click', 'setnewname')
        watch_demo.$destroy()

        //计算属性的 setter
        var watch_demo = new Vue({
            el: e,
            data: {
                firstName: 'Foo',
                lastName: 'Bar'
            },
            computed: {
                fullName: {
                    get: function () {
                        return this.firstName + ' ' + this.lastName
                    },
                    set: function (newValue) {
                        var names = newValue.split(' ')
                        this.firstName = names[0]
                        this.lastName = names[names.length - 1]
                    }
                }
            },
            methods: {
                setnewname: function () {
                    this.fullName = "这是 新的名字"
                }
            }

        })

        //深入了解组件
        //组件的名称使用驼峰命名时 如： Vue.component('MyComponentName', { /* ... */ })
        //html中使用 <my-component-name> 和 <MyComponentName> 都是可以引用该组件的

        // 定义一个名为 button-counter 的新组件
        Vue.component('button-counter', {
            data: function () {     //组件的data成员必须是一个函数，否制DOM上每个组件都是使用同一个data obj实例
                return {
                    count: 0
                }
            },
            template: '<button v-on:click="count++">你点击了我 {{ count }} 次.</button>'
        })

        //通过Vue.component()函数注册的组件是全局组件
        //局部组件的使用如下
        var LComponentA = {
            data: function () { },
            template: ''
        }
        var LComponentB = {
            components: {
                'component-a': LComponentA
            },
            // ...
        }
        new Vue({
            components: {
                'component-a': LComponentA,
                'component-b': LComponentB,
            }
        })

        //通过标签<>里的attribute向组件传递数据  props
        Vue.component('blog-post', {
            //由于html属性名都会转为小写，所以vue里的props指定的名称一般使用短横线分隔
            //如果使用了驼峰命名，vue也会转换为短横线分隔，html引用时要注意
            //但是， 使用字符串模板，那么这个限制就不存在了
            props: ['title'],       //声明该组件 接收<>标签里的 'title' 属性
            template: '<h3>{{ title }}</h3>'
        })
        //html中可以这样使用
        // <blog-post title="My journey with Vue"></blog-post>
        // <blog-post title="Blogging with Vue"></blog-post>
        // <blog-post title="Why Vue is so fun"></blog-post>

        // props也可以转入对象
        // var c = {
        //     props: {
        //         title: String,
        //         likes: Number,
        //         isPublished: Boolean,
        //         commentIds: Array,
        //         author: Object,
        //         callback: Function,
        //         contactsPromise: Promise // or any other constructor
        //     }
        // }
        //好处是不仅为你的组件提供了文档，还会在它们遇到错误的类型时从浏览器的 
        // JavaScript 控制台提示用户。

        //传入一个对象的所有 property
        // post: {
        // id: 1,
        // title: 'My Journey with Vue'
        // }
        //<blog-post v-bind="post"></blog-post>

        //props 验证和默认值
        var c = {
            props: {
                attriA: {
                    type: Number,   //类型
                    default: 100,    //默认值
                    validator: function (value) {   //验证函数
                        return typeof (value) === "number"
                    }
                },
            }
        }

        //props 类型检查
        function Person() {
            this.name = "";
        }
        var c = {
            props: {
                attr: Person
            }
        }

        //没有用props声明的html属性 会生成到渲染结果中
        //例如 <component nonprop="123"></component> 会渲染成 <div nonprop="123">...</div>
        //可以通过 inheritAttrs: false 指定设置 非props的属性是不渲染到组件的根元素
        //这样就可以配合$attrs 手动设置这些非props放置到组件中那个元素上
        //注意 inheritAttrs: false 选项不会影响 style 和 class 的绑定。
        //例如
        Vue.component('attrs-manual-place', {
            inheritAttrs: false,
            props: ['label', 'value'],
            template: `
                <label>
                    {{ label }}
                    <input
                    v-bind="$attrs"
                    v-bind:value="value"
                    v-on:input="$emit('input', $event.target.value)"
                    >
                </label>
                `
        })


        //class style html属性的自动合并
        //如果 <bootstrap-date-input> 渲染成这样 <input type="date" class="form-control">
        //假设 使用时 class写入其它内容 
        // <bootstrap-date-input type="text" class="date-picker-theme-dark"></bootstrap-date-input>
        //那么渲染就会变成这样子
        //<input type="text" class="form-control date-picker-theme-dark">
        //自动合并仅对 class 和 style起作用，
        //其它的属性会在渲染时被上级定义替换，例如上面的 type 属性

        //组件中自定义事件
        //通过$emit 发送组件自定义消息
        //不同于组件和 prop，$emit发送事件名不存在任何自动化的大小写转换。
        //v-on 事件监听器在 DOM 模板中会被自动转换为全小写
        //所以 v-on:myEvent 将会变成 v-on:myevent——导致 myEvent 不可能被监听到
        //所以 推荐你始终使用 kebab-case 的事件名。
        Vue.component('component-even', {
            props: ['post'],
            data: function () {
                return {
                    count: 0
                }
            },
            template: `
           <div>
                <h3>{{ post }}</h3>
                <button v-on:click="count=count+1;$emit('def-even1',count,2)">
                    $emit事件
                </button>
           </div>
        `
        })

        var component_e1 = new Vue(
            {
                el: "#component-e1",
                data: {
                    msg: "点击按钮触发组件内自定义事件"
                },
                methods: {
                    changemsg: function (arg1, arg2) {
                        this.msg = "接收到来自组件的 $emit 发送事件！" + " 事件参数1:" + arg1 + " 事件参数2:" + arg2
                    }
                }
            }
        )

        //组件上的v-model
        // vue 中v-model <input v-model="searchText"> 
        // 实际是等价于 ： 
        // <input v-bind:value="searchText" v-on:input="searchText = $event.target.value">
        // $event.target.value 返回事件DOM的value值
        // 当用在组件上时，v-model 则会这样：
        // <custom-input
        // v-bind:value="searchText"
        // v-on:input="searchText = $event"
        // ></custom-input>
        // 所以 要让组件的 v-model起作用，需要一个 props:[value,...] 和$emit发送带参数input事件
        Vue.component('custom-input', {
            props: ['value'],
            //v-bind:value="value" 是使 组件内的input的 value属性绑定到vue实例的value成员
            //v-on:input="$emit('input', $event.target.value)" 是当组件内的
            //input标签的input事件发生时 
            //向外发送 组件的 input 信号 
            template: `
            <div>
                <input
                v-bind:value="value"
                v-on:input="$emit('input', $event.target.value)"
                >
            </div>
            `
        })
        //注意 这里emit发送的$event是原生dom事件转入的 event

        var custom_input1 = new Vue(
            {
                el: '#custom-input-demo',
                data: {
                    searchText: "组件的 v-model"
                }
            }
        )

        //一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件，
        // 但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。
        // model 选项可以用来避免这样的冲突：
        Vue.component('base-checkbox-model-modify', {
            model: {
                prop: 'checked',
                event: 'change'
            },
            props: {
                checked: Boolean
            },
            template: `
                <input
                    type="checkbox"
                    v-bind:checked="checked"
                    v-on:change="$emit('change', $event.target.checked)"
                >
                `
        })

        //将原生事件绑定到组件
        //例如 想响应组件根元素的 focus 事件 可以这样子写
        //<base-input v-on:focus.native="onFocus"></base-input>
        //但是 在组件的模板为根元素为一些特定类型时 如 label
        // <label>
        //  {{ label }}
        //  <input
        //  v-bind="$attrs"
        //  v-bind:value="value"
        //  v-on:input="$emit('input', $event.target.value)"
        //  >
        // </label>
        //这时，父级的 .native 监听器将静默失败。它不会产生任何报错，
        //但是 onFocus 处理函数不会如你预期地被调用。
        // 为了解决这个问题，Vue 提供了一个 $listeners property，它是一个对象，
        // 里面包含了作用在这个组件上的所有监听器。例如：
        // {
        //   focus: function (event) { /* ... */ }
        //   input: function (value) { /* ... */ },
        // }
        //有了这个 $listeners property，你就可以配合 v-on="$listeners" 
        //将所有的事件监听器指向这个组件的某个特定的子元素。
        //下面的代码 使组件成为一个完全透明的包裹器了
        Vue.component('base-input-native', {
            inheritAttrs: false,
            props: ['label', 'value'],
            computed: {
                inputListeners: function () {
                    var vm = this
                    // `Object.assign` 将所有的对象合并为一个新对象
                    return Object.assign({},
                        // 我们从父级添加所有的监听器
                        this.$listeners,
                        // 然后我们添加自定义监听器，
                        // 或覆写一些监听器的行为
                        {
                            // 这里确保组件配合 `v-model` 的工作
                            input: function (event) {
                                vm.$emit('input', event.target.value)
                            }
                        }
                    )
                }
            },
            template: `
                <label>
                {{ label }}
                <input
                    v-bind="$attrs"
                    v-bind:value="value"
                    v-on="inputListeners"
                >
                </label>
            `
        })

        //.sync 修饰符 
        //这个修饰符是利用 update:xxxx 自定义事件 对props进行相向绑定的
        //例如 <text-document v-bind:title.sync="doc.title"></text-document> 相当于
        //<text-document v-bind:title="doc.title" v-on:update:title="doc.title = $event"></text-document>
        //这时就可以通过 this.$emit('update:title', newTitle) 在组件时对父vue实例的props进行修改了
        //当我们用一个对象同时设置多个 prop 的时候，也可以将这个 .sync 修饰符和 v-bind 配合使用：
        //<text-document v-bind.sync="doc"></text-document>
        //这样会把 doc 对象中的每一个 property (如 title) 都作为一个独立的 prop 传进去，
        //然后各自添加用于更新的 v-on 监听器。
        //注意的是 v-bind.sync=”{ title: doc.title }”，是无法正常工作的


        //插槽的使用
        //插槽内可以包含任何模板代码，包括 HTML ，甚至其它的组件、vue js表达式
        //<slot>后备内容</slot> 包裹的内容是后备内容，它在html使用组件时没有指定内容时渲染显示
        Vue.component('alert-box', {
            //<alert-box></alert-box>包含的内容会替换到模板的 <slot></slot> 位置
            template: `
            <div class="demo-alert-box">
                <strong>slot示例 : </strong>
                <slot>后备内容</slot>
            </div>
            `
        })

        new Vue(
            {
                el: "#slot-demo1"
            }
        )


        //命名插槽
        var nameslotdemo = new Vue({
            el: "#name-slot-demo",
            components: {
                "name-slot-div": {
                    template: `
                    <div class="container">
                        <header></header>
                        <ol>
                            <li>
                                <slot name="header"></slot>
                            </li>
                            <li>
                                <slot></slot>
                            </li>
                            <li>
                                <slot name="footer"></slot>
                            </li>
                        </ol>
                    </div>
                `
                }
            }
        })

        //插槽 prop
        //插槽 prop可以让 html的中的template标签里的表达式访问到组件中的数据
        //使用v-bind 声明该slot内那个对象输出到父级 
        var slotpropdemo = new Vue({
            el: '#slot-prop-demo',
            components: {
                'slot-prop-div': {
                    data: function () {
                        return {
                            user: {
                                firstName: "firstName=姓",
                                lastName: "lastName=名"
                            }
                        }
                    },
                    template: `
                    <span>
                        <slot v-bind:shell="user">
                            备用的内容为 {{ user.lastName }}
                        </slot>
                    </span>
                    `
                }
            }
        })

        //动态组件
        new Vue(
            {
                el: '#dync-component-demo',
                data: {
                    dync1: 'todo-item',
                    dync2: 'button-counter',
                    dync1_list: [
                        { id: 0, text: '测试1' },
                        { id: 1, text: '测试2' },
                        { id: 2, text: '测试3' },
                    ]
                }
            }
        )

        //异步组件
        //应该就是通过函数来获取组件对象
        //例子：
        Vue.component('async-example', function (resolve, reject) { //这里转入了两个函数 resolve reject
            setTimeout(function () {
                // 向 `resolve` 回调函数 传送组件定义
                resolve({
                    template: '<div>I am async!</div>'
                })
            }, 1000)
        })
        //你从服务器得到组件定义的时候调用 resolve 这个回调函数 返回得到的组件对象
        //也可以调用 reject(reason) 来表示加载失败

        //一个推荐的做法是将异步组件和 webpack 的 code-splitting 功能一起配合使用：
        Vue.component('async-webpack-example', function (resolve) {
            // 这个特殊的 `require` 语法将会告诉 webpack
            // 自动将你的构建代码切割成多个包，这些包
            // 会通过 Ajax 请求加载
            require(['./my-async-component'], resolve)
        })
        // 这里的异步组件工厂函数也可以返回一个如下格式的对象：

        const AsyncComponent = () => ({
            // 需要加载的组件 (应该是一个 `Promise` 对象)
            component: import('./MyComponent.vue'),
            // 异步组件加载时使用的组件
            loading: LoadingComponent,
            // 加载失败时使用的组件
            error: ErrorComponent,
            // 展示加载时组件的延时时间。默认值是 200 (毫秒)
            delay: 200,
            // 如果提供了超时时间且组件加载也超时了，
            // 则使用加载失败时使用的组件。默认值是：`Infinity`
            timeout: 3000
        })

        //混入 
        //这个示例 使用Vue.extend() 将东西挂载到body最后
        //extend返回的是 构造器，不是组件
        var testMixin1 = Vue.extend({
            template: '<div>{{ text }}</div>',
            data: function () {
                return {
                    text: 'mixin 测试1'
                }
            }
        })
        mixin1 = new testMixin1()
        mixin1.$mount('#mixinflag')

        //混合选项合并
        var mixin = {
            //data 对象与被混入的vue冲突时，以被混入的vue为准，否则合并
            data: function () {
                return {
                    message: 'hello',
                    foo: 'abc'
                }
            },
            //被混入的vue template非空时，使用被混合的template
            template: `
                <p>这里是混入的模板 &lt;p&gt;</p>
            `
        }
        new Vue({
            mixins: [mixin],    //mixin以数组形式输入
            data: function () {
                return {
                    message: 'goodbye',
                    bar: 'def'
                }
            },
            template: `
                <div style='background-color:lightgrey'>
                    <h5>混合选项合并</h5>
                    <p> message:{{message}} ,
                        bar:{{bar}} ,
                        foo:{{foo}} ,
                    </p>
                </div>
            `,
            created: function () {
                console.log(this.$data)
                // => { message: "goodbye", foo: "abc", bar: "def" }
            }
        }).$mount('#mixin-opt-merge')

        //同名钩子函数将合并为一个数组，因此都将被调用。
        //另外，混入对象的钩子将在组件自身钩子之前调用
        var mixin = {
            created: function () {
                console.log('混入对象的钩子被调用')
            }
        }

        new Vue({
            mixins: [mixin],
            created: function () {
                console.log('组件钩子被调用')
            }
        })

        //值为对象的选项，例如 methods、components 和 directives，
        //将被合并为同一个对象。两个对象键名冲突时，取组件对象的键值对。


        //自定义指令示例
        // 注册一个全局自定义指令 `v-focus`
        // Vue.directive('focus', {
        //     // 当被绑定的元素插入到 DOM 中时……
        //     inserted: function (el) {
        //         // 聚焦元素
        //         el.focus()
        //     }
        // })
        //使用方法 <input v-focus>
        //一个指令定义对象可以提供如下几个钩子函数 (均为可选)：
        //bind：只调用一次，指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
        //inserted：被绑定元素插入父节点时调用(并不是指插入到DOM)
        //update：所在组件的 VNode 更新时调用
        //componentUpdated：指令所在组件的 VNode 及其子 VNode 全部更新后调用
        //unbind：只调用一次，指令与元素解绑时调用

        //render()函数
        //代替template 生成dom的例子
        new Vue({   //根据level属性生成 html标题
            el: '#vue-render-demo',
            data: {
                level: 6
            },
            components: {
                'vue-render-demo': {
                    props: {
                        level: {
                            type: Number,
                            required: true
                        }
                    },
                    render: function (createElement) { //createElement是vue输入的生成vnode对象的函数
                        return createElement(
                            'h' + this.level,   //第一个参数是标签，这里由level生成 'h6'
                            this.$slots.default  //第二个参数是子vnode对象，这里是slot 的default内容
                        )
                    }
                }
            }
        })

        // createElement函数简介
        //createElement(
        // // {String | Object | Function}
        // // 一个 HTML 标签名、组件选项对象，或者
        // // resolve 了上述任何一种的一个 async 函数。必填项。
        // 'div',

        // // {Object}
        // // 一个与模板中 attribute 对应的数据对象。可选。
        // {
        //     
        // },

        // // {String | Array}
        // // 子级虚拟节点 (VNodes)，由 `createElement()` 构建而成，
        // // 也可以使用字符串来生成“文本虚拟节点”。可选。
        // [
        //     '先写一些文字',
        //     createElement('h1', '一则头条'),
        //     createElement(MyComponent, {
        //     props: {
        //         someProp: 'foobar'
        //     }
        //     })
        // ]
        // )

        //Vue.compile() 模板编译函数
        var compile_demo = new Vue({
            data: {
                msg: "用Vue.compile() 和 _c() 合成渲染函数 _render() \n 3秒后改变模板"
            }
        })
        compile_demo._compiledTemplate = Vue.compile(
            `
            <div style='background-color:lightgrey'>
            <h2>Vue.complie() 编译html模板</h2>
            <p>{{msg}}</p>
            </div>
            `
        )
        compile_demo._render = function () {
            return compile_demo._compiledTemplate.render.call(compile_demo, compile_demo._c)
        }
        compile_demo.$mount('#vue-compile-demo')

        setTimeout(() => {
            compile_demo._compiledTemplate = Vue.compile(
                `
            <div style='background-color:lightgrey'>
            <h2>Vue.complie() 编译html模板</h2>
            <ul>
                <li>1 : {{msg}}</li>
                <li v-for='item in listdata'>{{item}}</li>
            </ul>
            </div>
            `
            )
            compile_demo.listdata = []
            compile_demo.$set(compile_demo,
                "listdata",
                ['这里是行1,使用$set()动态添加响应式属性!',
                    '这里是行2,使用$set()动态添加响应式属性!']
            )
            compile_demo._render = function () {
                return compile_demo._compiledTemplate.render.call(compile_demo, compile_demo._c)
            }
            compile_demo._vnode = compile_demo.$el
            compile_demo._update(compile_demo._render())
        }, 3000);

        //createElement 深入
        //详细见 https://cn.vuejs.org/v2/guide/render-function.html#%E6%B7%B1%E5%85%A5%E6%95%B0%E6%8D%AE%E5%AF%B9%E8%B1%A1
        // 渲染函数 & JSX 的 深入数据对象
        new Vue({
            template: `<test myProp="this is test myProp" >  this is slot msg. </test>`,
            components: {
                'test': {
                    data: function () {
                        return {
                            refprop: '相当于{{}}引用',
                            myclass: '1st',
                            classdemo: '2nd',
                            styleobj: 'color:yellow; background-color:red '
                        }
                    },
                    render: function (h) {
                        return h('div', { class: 'test', attrs: { MyAttr: 'somesome', name: 'mytest' }, style: 'background-color:gray;' },
                            [h('h1', '这里是h1'), h('h2', '这里是h2'),
                            h('p',
                                {
                                    domProps: {
                                        innerHTML: '这里是段落 || ' + this.refprop + '<br> 组件props : ' + this.myProp
                                    },

                                    attrs: { 'attr-test': 'hello', MyAttr: '123', id: 'p11111' },
                                    class: [this.myclass, this.classdemo],
                                    style: this.styleobj
                                },
                            ),
                            h('p', this.$slots.default)
                            ]
                        )
                    },
                    props: {
                        myProp: String
                    },
                }
            }
        }
        ).$mount(document.getElementById('vue-render-demo1'))

        //vue router 学习

        // 0. 如果使用模块化机制编程，导入Vue和VueRouter，要调用 Vue.use(VueRouter)

        // 1. 定义 (路由) 组件。
        // 可以从其他文件 import 进来
        var Foo = { template: '<div>foo</div>' }
        var Bar = { template: '<div>bar</div>' }

        // 2. 定义路由
        // 每个路由应该映射一个组件。 其中"component" 可以是
        // 通过 Vue.extend() 创建的组件构造器，
        // 或者，只是一个组件配置对象。
        //path 是指http主页下的 子路径 如果主页是localhost/index.html下面第一个对应  http://localhost/index.html#/foo
        var routes = [
            { path: '/foo', component: Foo },
            { path: '/bar', component: Bar }
        ]

        // 3. 创建 router 实例，然后传 `routes` 配置
        // 还可以传别的配置参数, 不过先这么简单着吧。
        var router = new VueRouter({
            routes // (缩写) 相当于 routes: routes
        })

        // 4. 创建和挂载根实例。
        // 记得要通过 router 配置参数注入路由，
        // 从而让整个应用都有路由功能
        var router_demo1 = new Vue({
            router
        }).$mount('#router-demo1')

        // 现在，应用已经启动了！

        //动态路由
        var User = {
            template: '<div>用户 {{ $route.params.id }}</div>',
            beforeRouteUpdate(to, from, next) {
                //响应路由参数的变化
                console.log("从路径" + from.path + "转到 -> " + to.path)
                next()  //如果允许跳转 必须调用，否则调用next(false)
            }
        }

        var router = new VueRouter({
            routes: [
                // 动态路径参数 以冒号开头
                //冒号后面是匹配关键字，可以为任意字符串
                //成功匹配到路径后，可以用$route.params.???访问到 
                { path: '/user/:id', component: User }
            ]
        })

        var router_demo2 = new Vue({
            router
        }).$mount('#router-demo2')

        //嵌套router
        var router = new VueRouter({
            routes: [
                {
                    path: "/embeddedview/:username",
                    component: {
                        template: `
                        <div style="background-color:lightpink">
                            <h6>这里是嵌套首层</h6>
                            <p>用户 {{ $route.params.username }}</p>
                            <router-link to="/embeddedview/foo/profile">跳转到嵌入二层profile</router-link>
                            <br>
                            <router-link to="/embeddedview/foo/posts">跳转到嵌入二层posts</router-link>
                            <br>
                            <router-view></router-view>
                        </div>
                        `
                    },
                    children: [
                        {
                            path: "profile", //路径不是 以 /开关是指相对于当前路径，而不是主页
                            component: {
                                template: `
                                <div style="background-color:green">
                                    <h6>这里是嵌套二层</h6>
                                    <p>这里是profile</p>
                                </div>
                                `
                            }
                        },
                        {
                            path: "posts",
                            component: {
                                template: `
                                <div style="background-color:red">
                                    <h6>这里是嵌套二层</h6>
                                    <p>这里是posts</p>
                                    <br>
                                </div>
                                `
                            }
                        }
                    ]
                }
            ]
        })

        var router_demo3 = new Vue({
            router
        }).$mount('#router-demo3')

        //编程式导航
        new Vue(
            {
                el: '#router-demo4',
                template: `
                <input type="button" value="跳转到/embeddedview/foo/profile" v-on:click='gopath1'></button>
                `,
                methods: {
                    gopath1() {
                        this.$router.push('/embeddedview/foo/profile')
                        // // 字符串
                        // router.push('home')

                        // // 对象
                        // router.push({ path: 'home' })

                        // // 命名的路由
                        // router.push({ name: 'user', params: { userId: '123' } })

                        // // 带查询参数，变成 /register?plan=private
                        // router.push({ path: 'register', query: { plan: 'private' } })

                        // 如果提供了 path，params 会被忽略，上述例子中的 query 并不属于这种情况
                        // const userId = '123'
                        // router.push({ name: 'user', params: { userId } }) // -> /user/123
                        // router.push({ path: `/user/${userId}` }) // -> /user/123
                        // // 这里的 params 不生效
                        // router.push({ path: '/user', params: { userId } }) // -> /user

                        //在 router.push 或 router.replace 中提供 
                        //onComplete 和 onAbort 回调作为第二个和第三个参数。这些回调将会在导航成功完成
                        //或终止的时候进行相应的调用
                        //在 3.1.0+，可以省略第二个和第三个参数，
                        //此时如果支持 Promise，router.push 或 router.replace 将返回一个 Promise

                        // 如果目的地和当前路由相同，只有参数发生了改变 (比如从一个用户资料到另一个 /users/1 -> /users/2)，
                        //你需要使用 beforeRouteUpdate 来响应这个变化 (比如抓取用户信息)

                        //router.replace()
                        //跟 router.push 很像，唯一的不同就是，它不会向 history 添加新记录

                        //router.go(n)
                        //这个方法的参数是一个整数，意思是在 history 记录中向前或者后退多少步，
                        //类似 window.history.go(n)。


                    }
                },
                router
            }
        )

        //命名路由
        var router = new VueRouter({
            routes: [
                // 动态路径参数 以冒号开头
                //冒号后面是匹配关键字，可以为任意字符串
                //成功匹配到路径后，可以用$route.params.???访问到 
                {
                    path: '/user/:userId',
                    name: 'namedrouter',
                    component: {
                        template: `
                        <p>这里是命名路由</p>
                        `
                    }
                }
            ]
        })

        var router_demo5 = new Vue({
            router
        }).$mount('#router-demo5')

        //命名视图
        var router = new VueRouter({
            routes: [
                // 动态路径参数 以冒号开头
                //冒号后面是匹配关键字，可以为任意字符串
                //成功匹配到路径后，可以用$route.params.???访问到 
                {
                    path: '/nameview',
                    components: {            //注意这里是components 不是 component,用于多视图的情况
                        default: {
                            template: `
                            <p style="background-color:red">这里是默认的无名视图</p>
                            `
                        },
                        v1: {
                            template: `
                            <p style="background-color:green">这里是视图v1</p>
                            `
                        },
                        v2: {
                            template: `
                            <div style="background-color:blue;color:white">
                            <p>这里是视图v2</p>
                            <br>
                            <router-link to="/nameview/embedded" style="color:white">跳转到命名视中的嵌套命名视图</router-link>
                            <router-view name="v2"></router-view>
                            </div>
                            `
                        }
                    },
                    children: [
                        {
                            path: 'embedded',
                            components: {
                                v2: {
                                    template: `
                                     <p style="background-color:yellow;color:black">这里是嵌套命名视图v2</p>
                                    `
                                }
                            }
                        }
                    ]
                }
            ]
        })

        var router_demo6 = new Vue({
            router
        }).$mount('#router-demo6')

        //路由组件传参
        var router = new VueRouter({
            routes: [
                {
                    path: '/proptovue/:id',
                    component: {
                        props: ['id'],  //类似到vue 从attribute转值到组件内部
                        //{{ id }}就可以直接访问到 路径的动态匹配值了，不用通过$router.params.id了
                        template: '<div>可从vue组件中读取到用户id = {{ id }}</div>'
                    },
                    props: true     // 如果 props 被设置为 true，route.params 将会被设置为组件属性。
                },

                // 对于包含命名视图的路由，你必须分别为每个命名视图添加 `props` 选项：
                // {
                //     path: '/user/:id',
                //     components: { default: User, sidebar: Sidebar },
                //     props: { default: true, sidebar: false }
                // }

                //如果 props 是一个对象，它会被按原样设置为组件属性。当 props 是静态的时候有用。
                {
                    path: '/proptovue-object/test',
                    component: {
                        props: ['newsletterPopup'],
                        template: `
                        <div>可从vue组件中读取对象props = {{ newsletterPopup }}</div>
                        `
                    },
                    props: { newsletterPopup: false }
                },

                //可以创建一个函数返回 props。这样你便可以将参数转换成另一种类型，将静态值与基于路由的值结合等等。
                {
                    path: '/proptovue-method/search',
                    component: {
                        props: ['query'],
                        template: `
                        <div>可从vue组件中读取函数props = {{ query }}</div>
                        `
                    },
                    props: route => ({ query: route.query.q })
                }
            ]
        })
        var router_demo7 = new Vue({
            router
        }).$mount('#router-demo7')


        ///////////////////////////////////////////////////////////////////////////
        document.body.onload = function () {  //body加载后 滚动到底部
            window.scrollTo(0, document.body.scrollHeight);
        }
        document.body.onreset = function () {  //body加载后 滚动到底部
            window.scrollTo(0, document.body.scrollHeight);
        }

    </script>

</body>

</html>